package com.qf.commons.web.exception;

import com.qf.commons.base.result.Codes;
import com.qf.commons.base.result.R;
import com.qf.commons.base.result.Rs;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @RestControllerAdvice -> 给所有的Controller套一层AOP的代理
 *
 * author Ken
 * create_time 2022/11/21
 */
@RestControllerAdvice
public class GlobalExceptionHandler implements ResponseBodyAdvice<R> {

    /**
     * 自定义业务异常的处理
     * @param e
     * @return
     */
    @ExceptionHandler(ServiceException.class)
    public R ServiceException(ServiceException e){
        return Rs.createFail(e.getCodes());
    }

    @ExceptionHandler(BindException.class)
    public R bindExceptionHandler(BindException e){
//        List<ObjectError> allErrors = e.getAllErrors();
//        List<String> erros = new ArrayList<>();
//        for (ObjectError allError : allErrors) {
//            String errInfo = allError.getDefaultMessage();
//            erros.add(errInfo);
//        }

        List<String> erros = e.getAllErrors().stream()
                .map(objectError -> objectError.getDefaultMessage())
                .collect(Collectors.toList());

        return Rs.createFail(Codes.PARAM_FAIL, erros);
    }

    @ExceptionHandler
    public R exceptionHandler(Throwable t){
        System.out.println("发生了全局异常！");
        t.printStackTrace();
        return Rs.createFail(Codes.FAIL);
    }

    /**
     * supports方法返回true时，beforeBodyWrite方法才会执行
     * @param returnType the return type
     * @param converterType the selected converter type
     * @return
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.getMethod().getReturnType() == R.class;
    }

    @Override
    public R beforeBodyWrite(R body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body.getCode() != Codes.SUCC.getCode()) {
            //手动修改Http层面的响应码 直接设置为500
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return body;
    }
}
